
using System;
using System.Collections;
using System.IO;
using System.Diagnostics;

using CStock;
using CUtil;
using CIndicators;


using Microsoft.Win32;
using System.Windows.Forms;
using CUtil.Excel;
using System.Data;

namespace CStock
{
    /// <summary>
    /// Summary description for 
    /// </summary>
    public partial class ProgramContext : StockObjectBase, IProgramContext, IDisposable
    {
        #region Fields

        private bool _disposed;
        //private string pathApplication;
        private IDataClass dataClassToAddInChartWindow;
        private string pathLogfile;
        private CUtil.LogFile logfile;
        private IConfiguration configuration;

        private bool excelOpenYesNo;


        private ITradeEconomy tradeEconomy;
        private ITrader trader_Simulation;

        private string excelFileDir;
        private string excelFileName;





        private System.Windows.Forms.HelpProvider helpProvider;
        CStock.ExcelReader excelReader;
        CUtil.Excel.ExcelWriter excelOrderBook = null;
        CUtil.Excel.ExcelWriter excelWriter;

        private string helpfile;

        public static string PathBin;

        private CUtil.IIndicatorComposed indicatorComposed;


        private bool isInitialized;



        #endregion

        #region static instance

        private static ProgramContext instance;
        private static IErrorDialog errorDialog;

        //for accessing it in Configuration
        public static ProgramContext Instance
        {
            get
            {
                CheckInstance();
                errorDialog = new ErrorDialog() as IErrorDialog;
                return ProgramContext.instance;
            }
        }
        public IErrorDialog ErrorDialog 
        {
            get
            {
                return errorDialog;

            }
        }


        /// <summary>
        /// If the instance is null when requested, provide a default, non-forced
        /// config'd ProgramContext.
        /// </summary>
        private static void CheckInstance()
        {
            if (ProgramContext.instance == null)
            {
                ProgramContext.instance = ProgramContext.CreateProgramContext(false);
                Debug.WriteLine("Provided default ProgramContext");
            }
        }

        #endregion

        #region Constructor


        private ProgramContext()
        {
            _disposed = false;
            ProgramContext.instance = this;
            InitLogfile();
        }

        /// <summary>
        /// Only the program Context creates a directory
        /// </summary>
        /// <param name=""></param>
        /// <param name="id"></param>
        private ProgramContext(string myPathBin, string id, bool forceNewConfig) : this()
        {
            this.path = myPathBin + "Data\\" + id;
            this.iD = id;
            this.Reg_GetExcelFile();

            if (excelOpenYesNo && this.excelFileName != null && this.excelFileName != string.Empty)
            {
                if (InitConfig(forceNewConfig))
                {
                    if (!this.GetEconomyFromExcelFile(this.excelFileName))
                    {
                        MessageBoxButtons buttons = MessageBoxButtons.YesNo;
                        if (System.Windows.Forms.MessageBox.Show("No valid program data found in Excel file - do you want to get data from local directory ?", "Update from local dir ? ", buttons) == DialogResult.Yes)
                        {
                            ProgramContext_Init(forceNewConfig);
                            //System.Windows.Forms.MessageBox.Show("No valid program data found in Excel file - pls. check! " + this.excelFileName);
                        }
                    }

                }
            }
            else
            {
                ProgramContext_Init(forceNewConfig);
            }


        }


        private void InitLogfile()
        {
            if (logfile == null)
            {

                pathLogfile = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Log");

                if (!System.IO.Directory.Exists(pathLogfile))
                    System.IO.Directory.CreateDirectory(pathLogfile);

                this.logfile = new LogFile(this.pathLogfile);
                this.logfile.WriteTimeLog("ProgramContext constructor");
                this.logfile.WriteTimeSpanLog("Configuration start");
            }
        }
        public bool Open_FromExcelFile(string excelFileName)
        {
            return GetEconomyFromExcelFile(excelFileName);
        }


        private IConfiguration OpenConfiguration(Stream myStream, string applicationDir)
        {
            object o = new Configuration();
            XMLSerializable.DeSerializeObject(ref o, myStream);
            IConfiguration myConfig = o as Configuration;
            myConfig.Directories.ApplicationPath = applicationDir;

            //openFileDialog1.FileName
            myStream.Close();
            return myConfig;
        }
        private void SaveInRegistry(string applicationDir)
        {
            //get the ID of the Program Context by directory structure
            //Get ID of ProgramContext from path
            string[] pathArray = applicationDir.Split(new char[] { '\\' }, 100);

            
            string newiD = pathArray[pathArray.GetLength(0) - 1];
            this.path = applicationDir;
           
            this.iD = newiD;
        }
        /// <summary>
        /// tries to open the Config file of one directory
        /// ignores the directory root from the file
        /// inserts the directory root from the path of the config file
        /// </summary>
        /// <returns></returns>
        public bool GetProgramConfigurationFromDirectory()
        {

            Stream myStream;

            
            System.Windows.Forms.OpenFileDialog openFileDialog1 = new OpenFileDialog();

            openFileDialog1.InitialDirectory = this.configuration.Directories.ApplicationPath;
            openFileDialog1.Filter = "Configuration files (*.xml)|*.xml|All files (*.*)|*.*";
            openFileDialog1.FilterIndex = 1;
            openFileDialog1.RestoreDirectory = true;

            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                if ((myStream = openFileDialog1.OpenFile()) != null)
                {
                    string strDirInitial = openFileDialog1.InitialDirectory;
                    //adjust this directory in Configuration
                    string applicationDir = IOUtil.ExtractFullPathFromFileName(openFileDialog1.FileName);

                    this.configuration = OpenConfiguration(myStream, applicationDir);
                    
                    ProgramContext_OpenOrCreate(applicationDir, false);

                    if (ProgramContext_Init(false))
                    {
                        string strPathNew = CUtil.IOUtil.CutLastTwoDirectories(path);
                        Reg_SaveLastPath(strPathNew, this.iD);
                    }
                }
            }
            return this.ProgramContext_Init(false);
        }

        private bool Reg_GetExcelFile()
        {
            RegistryKey MyReg = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Logisel\\CapitalResources\\0.90.18");
            if (MyReg != null)
            {
                object o = MyReg.GetValue("OpenExcel", false);
                this.excelOpenYesNo = Convert.ToBoolean(o);

                this.excelFileDir = MyReg.GetValue("Path_ExcelDir", null) as string;
                this.excelFileName = MyReg.GetValue("Path_ExcelFile", null) as string;
            }
            return true;

        }
        private bool Reg_WriteExcelFile()
        {
            RegistryKey MyReg = Registry.CurrentUser.CreateSubKey("SOFTWARE\\Logisel\\CapitalResources\\0.90.18");
          
            if (excelFileDir != null && excelFileDir != string.Empty)
                MyReg.SetValue("Path_ExcelDir", this.excelFileDir);
            if (!String.IsNullOrEmpty(excelFileName))
                MyReg.SetValue("Path_ExcelFile", excelFileName);

            MyReg.SetValue("OpenExcel", this.excelOpenYesNo);
            MyReg.Close();
            return true;
        }
        public static bool Reg_SaveLastPath(string myBinPath, string myID)
        {
            RegistryKey MyReg = Registry.CurrentUser.CreateSubKey("SOFTWARE\\Logisel\\CapitalResources\\0.90.18");
            MyReg.SetValue("Path_Bin", myBinPath);
            MyReg.SetValue("ID_Last", myID);
            MyReg.Close();
            return true;
        }
        public static bool Reg_ResetLastPath()
        {
            Registry.CurrentUser.DeleteSubKey("SOFTWARE\\Logisel\\CapitalResources\\0.90.18");
            return true;
        }
        public static bool Reg_GetLastPath(ref string myPathBin, ref string myID)
        {
            RegistryKey MyReg = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Logisel\\CapitalResources\\0.90.18");
            if (MyReg != null)
            {
                myPathBin = MyReg.GetValue("Path_Bin", null) as string;
                myID = MyReg.GetValue("ID_LAST", null) as string;
                MyReg.Close();

                if (myPathBin != null && myID != null && myPathBin != string.Empty && myID != string.Empty)
                {
                    return true;
                }
                Debug.WriteLine("Could not get registy values for last path");
                MyReg.Close();
            }
            else
            {
                //System.Windows.Forms.MessageBox.Show("Error openening registry key - please check installation");
                Debug.WriteLine("Could not get registy values for program");
                return false;
            }


            return false;
        }

        public bool DoMenuOpenExcelFile()
        {
            try
            {
      
                System.Windows.Forms.OpenFileDialog openFileDialog1 = new OpenFileDialog();
                if (!String.IsNullOrEmpty(excelFileDir))
                {
                    openFileDialog1.InitialDirectory = excelFileDir;

                }


                openFileDialog1.Filter = "Excel files (*.xls)|*.xls|All files (*.*)|*.*";
                openFileDialog1.FilterIndex = 1;
                openFileDialog1.RestoreDirectory = true;

                if (openFileDialog1.ShowDialog() == DialogResult.OK)
                {
                    if (openFileDialog1.FileName != null)
                    {
                        this.excelFileName = openFileDialog1.FileName;
                        if (this.Open_FromExcelFile(this.excelFileName))
                        {
                            this.Reg_WriteExcelFile();
                            return true;
                        }
                        else
                        {
                            System.Windows.Forms.MessageBox.Show("No valid program data found in Excel File - pls. check " + this.excelFileName);
                            return false;
                        }
                    }


                }
                return false;
            }
            catch (Exception ex)
            {
                Debug.Assert(false, "Error opening Excel file " + ex.Message);
                return false;
            }

        }


        public bool SaveAs()
        {
            Stream myStream;
            SaveFileDialog saveFileDialog1 = new SaveFileDialog();

            saveFileDialog1.InitialDirectory = this.configuration.Directories.ApplicationPath +
                this.configuration.Directories.IndicatorsComposedDir;
            saveFileDialog1.Filter = "Custom Indicator files (*.xml)|*.xml|All files (*.*)|*.*";
            saveFileDialog1.FilterIndex = 1;
            saveFileDialog1.RestoreDirectory = true;

            if (saveFileDialog1.ShowDialog() == DialogResult.OK)
            {


                if ((myStream = saveFileDialog1.OpenFile()) != null)
                {
                    //this.Cursor = System.Windows.Forms.Cursors.WaitCursor;

                    string[] arrStr = saveFileDialog1.FileName.Split(new Char[] { '\\' }, 100);
                    string strFileName = arrStr[arrStr.GetLength(0) - 1];
                    //string strDirectory = saveFileDialog1.FileName.Remove(saveFileDialog1.FileName.Length - strFileName.Length);

                    arrStr = strFileName.Split(new Char[] { '.' }, 100);
                    myStream.Close();



                }

                return true;
            }
            return false;

        }

        public override bool Delete()
        {
            //should also work with 
            logfile.Close();
            DirectoryInfo di = new DirectoryInfo(this.configuration.Directories.ApplicationPath);
            di.Delete(true);

            this.configuration.Directories.ApplicationPath = @"\";
            return true;
        }


        private bool InitConfig(bool forceNewConfig)
        {
            GetOrCreateConfiguration(forceNewConfig);
            if (this.configuration != null)
            {
                CIndicators.Indicator.StaticApplicationPath = this.Configuration.Directories.ApplicationPath;
                return true;
            }
            else
            {
                Debug.Assert(false, "Error getting config ");
            }

            return false;
        }
        public bool ProgramContext_OpenOrCreate(string myWorkingDir, bool create)
        {
            this.path = myWorkingDir;
            ProgramContext_Init(create);
            return true;

        }
        private void CreateNewEconomy()
        {
            System.Windows.Forms.MessageBox.Show("trade economy not existing - creating new one");

            //creates default economy - 
            TradeEconomyFactory tef = new TradeEconomyFactory();
            tef.Create_Default();
            tef.Serialize();
            this.tradeEconomy = tef.StockObjectBase as TradeEconomy;
            this.trader_Simulation = this.tradeEconomy;
        }
        private void CreateDefaultsForProgramContext()
        {
            this.logfile.WriteTimeSpanLog("Data initialized");
            this.tradeEconomy.SetDefaultPortfolioAndShare();
            this.tradeEconomy.TradeSimulation.SetDefaultTradeSystem();
            this.trader_Simulation = this.tradeEconomy;
            this.logfile.WriteTimeSpanLog("Default Portfolio and share");
        }
        /// <summary>
        /// Initializes path, gets or reads configuration
        /// </summary>
        public bool ProgramContext_Init(bool forceNewConfig)
        {
            try
            {
                this.Reg_WriteExcelFile();
                if (this.InitConfig(forceNewConfig))
                {
                    this.logfile.WriteTimeSpanLog("Configuration read");

                    if (this.DeSerialize() != null)
                    {
                        CreateDefaultsForProgramContext();
                    }
                    else
                    {
                        try
                        {
                            CreateNewEconomy();

                        }
                        catch (Exception exc)
                        {
                            System.Diagnostics.Debug.Assert(false, "Error at InitStocklogicData - no return! :" + exc.Message);
                            return false;
                        }
                    }

                    this.logfile.WriteTimeSpanLog("ProgramContext created:");
                    this.logfile.WriteTimeLog("ProgramContext created");
                }
                else
                {
                    return false;
                }

                isInitialized = true;
                this.Reg_WriteExcelFile();
                return true;
            }
            catch (Exception ex)
            {
                Debug.Assert(false, "Error in ProgramContext_Init: " + ex.Message);
                return false;

            }

        }
        /// <summary>
        /// CURRENTLY NOT USED!!!
        /// tries to open the Config file of one directory
        /// ignores the directory root from the file
        /// inserts the directory root from the path of the config file
        /// </summary>
        /// <returns></returns>
        public bool ProgramContext_OpenConfigurationFile()
        {

            Stream myStream;

            System.Windows.Forms.OpenFileDialog openFileDialog1 = new OpenFileDialog();

            openFileDialog1.InitialDirectory = this.configuration.Directories.ApplicationPath;
            openFileDialog1.Filter = "Configuration files (*.xml)|*.xml|All files (*.*)|*.*";
            openFileDialog1.FilterIndex = 1;
            openFileDialog1.RestoreDirectory = true;

            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                if ((myStream = openFileDialog1.OpenFile()) != null)
                {
                    string strDirInitial = openFileDialog1.InitialDirectory;

                    object o = new Configuration();
                    XMLSerializable.DeSerializeObject(ref o, myStream);
                    IConfiguration myConfig = o as Configuration;
                    string strDirectoryNew = myConfig.Directories.ApplicationPath;

                    //openFileDialog1.FileName
                    myStream.Close();
                    ProgramContext_OpenOrCreate(myConfig.Directories.ApplicationPath, false);

                    //get the ID of the Program Context by directory structure

                    string[] pathArray = strDirectoryNew.Split(new char[] { '\\' }, 100);


                    //Get pure file name
                    string newiD = pathArray[pathArray.GetLength(0) - 1];
                    this.path = string.Empty;
                    for (int i = 0; i < pathArray.GetLength(0) - 1; i++)
                        this.path += pathArray[i] + "\\";

                    this.path = strDirectoryNew;
                    this.configuration = myConfig;

                    this.iD = newiD;


                    if (ProgramContext_Init(false))
                    {
                        string strPathNew = CUtil.IOUtil.CutLastTwoDirectories(path);

                        Reg_SaveLastPath(strPathNew, this.iD);
                    }
                }
            }
            return this.ProgramContext_Init(false);
        }
        //
        /// <summary>
        /// Set the help provider only in UI mode - e.g. after the constructor in the MainForm
        /// </summary>
        public void SetHelpProvider()
        {
            helpProvider = new System.Windows.Forms.HelpProvider();
            helpfile = AppDomain.CurrentDomain.BaseDirectory + "\\Data\\CHelp.chm";
            if (!System.IO.File.Exists(helpfile))
            {
                Debug.Assert(false, "Helpfile: " + helpfile + " ; does not exist - please reinstall or copy helpfile to this location");
            }
            this.helpProvider.HelpNamespace = helpfile;
        }


        public void GetOrCreateConfiguration(bool forceNew)
        {
            if (forceNew)
            {
                CreateAndSaveConfiguration();
            }
            ConfigurationFactory cf = new ConfigurationFactory();

            try
            {
                if (cf.DeSerialize())
                {
                    
                    ProgramContext.Instance.Configuration = cf.StockObjectBase as IConfiguration;
                    this.configuration = ProgramContext.Instance.Configuration;
                    this.configuration.Directories.ApplicationPath = this.path;
                }
                else
                {
                    CreateAndSaveConfiguration();
                }
            }
            catch (Exception exc)
            {
                //this occurs at the first program start after the installation - then create a blanc configuration file
                //do nothing
                Debug.WriteLine("The configuration file is not here : " + exc.Message);
                CreateAndSaveConfiguration();
            }
        }

        private static Configuration Create_And_Save_Config(string myPath)
        {
            Debug.WriteLine("Creating new configuration file");
            Configuration myConfig = new CStock.Configuration();
            myConfig.SetNewPath(myPath);
            myConfig.Serialize();
            return myConfig;
        }
        private void CreateAndSaveConfiguration()
        {
            this.configuration = Create_And_Save_Config(this.path);
        }
        public bool SetNewPath_ID(string myPath, string myID)
        {
            this.path = myPath;
            this.iD = myID;

            if (this.configuration.SetNewPath(this.path + "\\Data\\" + iD))
            {
                ProgramContext.instance = this;
                return this.configuration.Serialize();
            }
            else
                return false;
        }
        #endregion

        #region properties IProgramContext

        public IConfiguration Configuration
        {
            get
            {
                return this.configuration;
            }
            set
            {
                this.configuration = value;
            }
        }

        public bool IsInitialized
        {
            get
            {
                return isInitialized;
            }
        }
        public CUtil.LogFile Logfile
        {
            get
            {
                return this.logfile;
            }
        }

        public ITradeEconomy TradeEconomy
        {
            get
            {
                return this.tradeEconomy;

            }
            set
            {
                this.tradeEconomy = value;
            }
        }
        public ITrader Trader_Simulation
        {
            get
            {
                return this.trader_Simulation;
            }
            set
            {
                this.trader_Simulation = value;
            }
        }
        public IDataClass DataClassToAddInChartWindow
        {
            get
            {
                return this.dataClassToAddInChartWindow;
            }
            set
            {
                this.dataClassToAddInChartWindow = value;
            }
        }





        /// <summary>
        /// 
        /// </summary>
        public System.Windows.Forms.HelpProvider HelpProvider
        {
            get
            {
                return this.helpProvider;
            }
        }
        //public string Path
        //{
        //    get
        //    {
        //        return this.pathApplication;
        //    }
        //    set
        //    {
        //        this.pathApplication = value;
        //    }
        //}


        /// <summary>
        /// 
        /// </summary>
        public string Helpfile
        {
            get
            {
                return this.helpfile;
            }
        }
        public IIndicatorComposed IndicatorComposed
        {
            get
            {
                return this.indicatorComposed;
            }
            set
            {
                this.indicatorComposed = value;

            }
        }



        #endregion

        #region create - save

        public bool OpenLastSaved()
        {
            Reg_GetLastPath(ref PathBin, ref this.iD);

            return this.ProgramContext_Init(false);

        }
        public static ProgramContext CreateProgramContext(string myPath, string myID, bool forceNewConfig)
        {
            CheckProgramContextInstance();
            ProgramContext myProgramContext = new ProgramContext(myPath, myID, forceNewConfig);

            myProgramContext.SetHelpProvider();
            return myProgramContext;
        }
        public static ProgramContext CreateProgramContext(bool forceNewConfig)
        {
            try
            {
                CheckProgramContextInstance();
                ProgramContext myProgramContext = new ProgramContext();

                string myPathBin = string.Empty;
                string myId = string.Empty;

                if (!CStock.ProgramContext.Reg_GetLastPath(ref myPathBin, ref myId))
                {
                    Debug.WriteLine("Could not read values from registry");

                }

                //check if binary path exists
                if (!System.IO.Directory.Exists(myPathBin))
                {
                    myPathBin = AppDomain.CurrentDomain.BaseDirectory;

                    if (String.IsNullOrEmpty(myId))
                        myId = "Default";
                    //Create_And_Save_Config(pathBin);
                }
                else
                {
                    if (String.IsNullOrEmpty(myPathBin) || !System.IO.Directory.Exists(myPathBin))
                    {
                        myPathBin = string.Empty;
                    }
                    if (String.IsNullOrEmpty(myId))
                        myId = "Default";

                }
                PathBin = myPathBin;
                CStock.ProgramContext.Reg_SaveLastPath(myPathBin, myId);

                return CreateProgramContext(myPathBin, myId, forceNewConfig);
            }
            catch (Exception ex)
            {
                Debug.Assert(false, "Error creating program context " + ex.Message);
                return null;
            }
        }

        private static void CheckProgramContextInstance()
        {
            if (ProgramContext.instance != null)
                ProgramContext.instance.Dispose();
        }


        /// <summary>
        /// name convention for portfolios: Contain the Trader name!!! Economy_Portfolio1
        /// </summary>
        /// <returns></returns>
        public override bool Serialize()
        {

            Reg_SaveLastPath(PathBin, this.iD);
            this.configuration.Serialize();
            return this.tradeEconomy.Serialize();


        }
        /// <summary>
        /// name convention for portfolios: Contain the Trader name!!! Economy_Portfolio1
        /// </summary>
        /// <returns></returns>
        public bool Save()
        {

            return this.Serialize();


        }
        /// <summary>
        /// name convention for portfolios: Contain the Trader name!!! Economy_Portfolio1
        /// </summary>
        /// <returns></returns>
        public override object DeSerialize()
        {
            //creates Factory
            TradeEconomyFactory tef = new TradeEconomyFactory();
            try
            {
                this.tradeEconomy = tef.StockObjectBase as TradeEconomy;
                this.trader_Simulation = this.tradeEconomy;
                //tef.StockObjectBase.SetPath(this.configuration.Directories.TradeEconomyPath);
                //tries to deserialze
                if (!tef.DeSerialize())
                {

                    //already created a new one in the Deserialize method
                    System.Windows.Forms.MessageBox.Show("Creating new trade economy " + this.tradeEconomy.ID);
                    tef.Create_Default();
                    tef.Serialize();
                }
                this.tradeEconomy = tef.StockObjectBase as TradeEconomy;
                this.trader_Simulation = this.tradeEconomy;

                return this;
            }
            catch (Exception e)
            {
                MessageBox.Show("Error deserializing ProgramContext " + e.Message);
                System.Diagnostics.Debug.WriteLine("Error deserializing: " + e.Message);
                return null;

            }

        }
        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    if (this.logfile != null)
                    {
                        this.logfile.Dispose();
                    }
                }
                this.logfile = null;
                ProgramContext.instance = null;
                _disposed = true;
            }
        }

        #endregion
    }
}
